﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CacheHelper.cs" company="Collaboris Ltd.">
//   Copyright (c) Collaboris Ltd. All rights Reserved.
// </copyright>
// <summary>
//   Defines the PageLayoutHelper type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace Collaboris.SharePoint.Moss.Publishing
{
    using System.IO;
    using System.Web;

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Publishing;
    using Microsoft.SharePoint.Publishing.Navigation;

    using Utils;

    /// <summary>
    /// This helper library is responsible for wrapping some calls
    /// on the whole to the Portal Site Map Provider.
    /// It will also deal with calls to CrossListQuery object.
    /// Consider using this methods, when you are accessing lists
    /// that are outside of your current context and also hit several 
    /// times. 
    /// 
    /// These classes aren't as rich as their SPList and SPlistItem cousins
    /// but nearly always perform many many times faster.
    /// </summary>
    public class CacheHelper : MossHelperBase
    {
        /// <summary>
        /// Gets the default page for a given web site.
        /// </summary>
        /// <param name="web">The web.</param>
        /// <returns></returns>
        public static string GetDefaultPage(SPWeb web)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "CacheHelper", "GetDefaultPage");

            // configure a site map provider
            PortalSiteMapProvider portProv = GetPortalProvider();

            string defaultPageUrl = string.Empty;

            // gets the web Node for top level site collection.
            PortalWebSiteMapNode webNode = GetWebSiteNode(web.ServerRelativeUrl);

            if (webNode != null)
            {
                defaultPageUrl = webNode.Url;
            }

            TraceHelper.TraceMethodEnd(TraceSwitch, "CacheHelper", "GetDefaultPage");

            return defaultPageUrl;
        }

        /// <summary>
        /// Gets the list items using the Default Views query.
        /// </summary>
        /// <param name="list">The list.</param>
        /// <returns>
        /// SiteMapNodeCollection containing all the items in the list
        /// </returns>
        public static SiteMapNodeCollection GetListItems(SPList list)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "CacheHelper", "GetListItems");

            // create the Query
            SPQuery query = new SPQuery();
            query.Query = query.Query = list.DefaultView.Query;

            TraceHelper.TraceMethodEnd(TraceSwitch, "CacheHelper", "GetListItems");
            return GetListItems(list, query);
        }

        /// <summary>
        /// Gets the list items for a specific query
        /// </summary>
        /// <param name="list">The list.</param>
        /// <param name="query">The query.</param>
        /// <returns>SiteMapNodeCollection containing a filtered version of the items in the list</returns>
        public static SiteMapNodeCollection GetListItems(SPList list, SPQuery query)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "CacheHelper", "GetListItems");

            PortalSiteMapProvider portProv = GetPortalProvider();
            SPWeb targetWeb = list.ParentWeb;

            // Lets get a reference to the Parent node that contains the list.
            PortalWebSiteMapNode targetNode = GetWebSiteNode(targetWeb.ServerRelativeUrl);

            if (targetNode == null)
            {
                TraceHelper.TraceMethodEnd(TraceSwitch, "CacheHelper", "GetListItems");
                return null;
            }

            // lets run the query
            SiteMapNodeCollection coll = portProv.GetCachedListItemsByQuery(
                    targetNode,
                    list.Title,
                    query,
                    targetWeb);

            TraceHelper.TraceMethodEnd(TraceSwitch, "CacheHelper", "GetListItems");
            return coll;
        }

        /// <summary>
        /// Gets a particular propety from the a page passed in by url
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <returns>an object representing the property; otherwise null</returns>
        public static object GetPropertyFromPage(SPList list, string pageName, string propertyName)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "CacheHelper", "GetPropertyFromPage");

            PortalListItemSiteMapNode foundNode = GetPageFromList(list, pageName);
            if (foundNode == null)
                return null;

            object val = foundNode[propertyName];
            if (val != null)
            {
                //TODO: lets use a generic here
                return val;
            }

            TraceHelper.TraceMethodEnd(TraceSwitch, "CacheHelper", "GetPropertyFromPage");
            return null;
        }

        /// <summary>
        /// Gets the page from list.
        /// </summary>
        /// <param name="list">The list.</param>
        /// <param name="pageName">Name of the page.</param>
        /// <returns></returns>
        public static PortalListItemSiteMapNode GetPageFromList(SPList list, string pageName)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "CacheHelper", "GetPageFromList");

            SPQuery query = new SPQuery();

            query.Query = QueryOnFileName(pageName);
            query.RowLimit = 2000;

            SiteMapNodeCollection coll = GetListItems(list, query);

            if (coll == null)
                return null;

            if (coll.Count < 1)
                return null;

            PortalListItemSiteMapNode foundNode = coll[0] as PortalListItemSiteMapNode;

            TraceHelper.TraceMethodEnd(TraceSwitch, "CacheHelper", "GetPageFromList");
            return foundNode;
        }

        /// <summary>
        /// Gets the web site node for the given url.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <returns></returns>
        public static PortalWebSiteMapNode GetWebSiteNode(string url)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "CacheHelper", "GetWebSiteNode");

            PortalSiteMapProvider portProv = GetPortalProvider();
            PortalWebSiteMapNode webNode = portProv.FindSiteMapNode(url) as PortalWebSiteMapNode;

            TraceHelper.TraceMethodEnd(TraceSwitch, "CacheHelper", "GetWebSiteNode");
            return webNode;
        }

        /// <summary>
        /// Gets the list item node.
        /// </summary>
        /// <remarks>
        /// Note. This will NOT return the default page as a WebSiteMapNode is returned
        /// instead. To get the default Page you must run a query.
        /// </remarks>
        /// <param name="url">The URL.</param>
        /// <returns></returns>
        public static PortalListItemSiteMapNode GetListItemNode(string url)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "CacheHelper", "GetListItemNode");

            PortalSiteMapProvider portProv = GetPortalProvider();
            PortalListItemSiteMapNode itemNode = portProv.FindSiteMapNode(url) as PortalListItemSiteMapNode;

            TraceHelper.TraceMethodEnd(TraceSwitch, "CacheHelper", "GetListItemNode");
            return itemNode;
        }

        /// <summary>
        /// Gets a reference to the WebSiteMapProvider
        /// </summary>
        /// <returns></returns>
        private static PortalSiteMapProvider GetPortalProvider()
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "CacheHelper", "GetPortalProvider");
            
            PortalSiteMapProvider portalProvider = new PortalSiteMapProvider();
            portalProvider.IncludePages = PortalSiteMapProvider.IncludeOption.Always;
            portalProvider.IncludeHeadings = false;
            portalProvider.IncludeSubSites = PortalSiteMapProvider.IncludeOption.Always;
            portalProvider.NavigationType = PortalNavigationType.Combined;

            TraceHelper.TraceMethodEnd(TraceSwitch, "CacheHelper", "GetPortalProvider");
            return portalProvider;
        }

        /// <summary>
        /// Filters the name of the on file.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <returns></returns>
        private static string QueryOnFileName(string fileName)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "CacheHelper", "QueryOnFileName");
            if (fileName.Contains("/"))
            {
                fileName = fileName.Substring(fileName.LastIndexOf("/") + 1);
            }

            System.Text.StringBuilder oSb = new System.Text.StringBuilder();

            oSb.Append("     <Query xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\">");
            oSb.Append("         <Where>");
            oSb.Append("              <Eq>");
            oSb.Append("                   <FieldRef Name=\"FileLeafRef\" />");
            oSb.AppendFormat("                   <Value Type=\"Text\">{0}</Value>", fileName);
            oSb.Append("              </Eq>");
            oSb.Append("         </Where>");
            oSb.Append("         <OrderBy>");
            oSb.Append("              <FieldRef Name=\"FileLeafRef\" />");
            oSb.Append("         </OrderBy>");
            oSb.Append("    </Query>");

            TraceHelper.TraceMethodEnd(TraceSwitch, "CacheHelper", "QueryOnFileName");
            return oSb.ToString();
        }

        /// <summary>
        /// Writes the an XML Representation of the current cache contents
        /// to a file. 
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="site">The site.</param>
        public static void WriteObjectCacheToFile(string path, SPSite site)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "CacheHelper", "WriteObjectCacheToFile");

            ValidationHelper.VerifyObjectArgument(site, "site");
            ValidationHelper.VerifyObjectArgument(path, "path");

            if (File.Exists(path))
                File.Delete(path);

            FileStream str = new FileStream(path, FileMode.CreateNew);
            PublishingCache.ListCacheContents(str, site);

            TraceHelper.TraceMethodEnd(TraceSwitch, "CacheHelper", "WriteObjectCacheToFile");
        }
    }
}